package cn.learn.async.threadpool;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 线程池
 * https://www.jianshu.com/p/c41e942bcd64
 *
 * @author huangyezhan
 * @version 1.0
 * @date 2021年08月25日16:09
 */
@Slf4j
public enum ThreadPoolUtil {
    /**
     * 单例对象
     */
    INSTANCE;

    /**
     * 线程池
     */
    private final ThreadPoolExecutor executor;

    /**
     * 失败线程的数量
     */
    private final AtomicInteger failedCount = new AtomicInteger(0);

    /**
     * 获取线程池
     */
    public ThreadPoolExecutor getExecutor() {
        return executor;
    }

    /**
     * 获取失败的总数量
     */
    public int getFailedCount() {
        return failedCount.get();
    }

    private ThreadPoolUtil() {
        int                           cpuNum        = Runtime.getRuntime().availableProcessors();
        LinkedBlockingQueue<Runnable> blockingQueue = new LinkedBlockingQueue<>(1000);
        ThreadFactory                 threadFactory = new NameTreadFactory();
        RejectedExecutionHandler      handler       = new MyIgnorePolicy();

        executor = new ThreadPoolExecutor(cpuNum, cpuNum * 2,
                60 * 30,
                TimeUnit.SECONDS,
                blockingQueue,
                threadFactory,
                handler);
    }

    /**
     * 线程工厂
     */
    static class NameTreadFactory implements ThreadFactory {
        private final AtomicInteger mThreadNum = new AtomicInteger(1);

        @Override
        public Thread newThread(Runnable runnable) {
            // 定义线程名称
            Thread thread = new Thread(runnable, "my-thread-" + mThreadNum.getAndIncrement());
            log.info(thread.getName() + " has been created");
            return thread;
        }
    }

    /**
     * 自定义拒绝策略
     */
    private class MyIgnorePolicy implements RejectedExecutionHandler {
        // 这个方法，如果不抛异常，则执行此任务的线程会一直阻塞
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            int count = failedCount.incrementAndGet();
            log.error("失败线程总数量达到：" + count + "失败了，超过线程池容纳数量：" + e.toString());
        }
    }

}
